package GUI.ElementTree;

import B3D_Elements.B3D_Element;
import B3D_Elements.B3D_Filters.B3D_Filter;
import B3D_Elements.B3D_Filters.B3D_Shadows.B3D_Shadow;
import B3D_Elements.B3D_Lights.B3D_Light;
import B3D_Elements.B3D_Spatials.B3D_Spatial;
import B3D_Elements.Others.B3D_MotionEvent;
import GUI.Dialogs.AdditionalCameraDialog;
import GUI.EditPanes.Other.MotionPathTaskPane;
import GUI.EditorMenu.AddMenu;
import General.CurrentData;
import com.jme3.cinematic.PlayState;
import com.jme3.cinematic.events.MotionEvent;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.light.Light;
import com.jme3.light.PointLight;
import com.jme3.light.SpotLight;
import com.jme3.math.Vector3f;
import com.jme3.post.Filter;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import other.ElementToObjectConverter;
import other.ObjectToElementConverter;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.dnd.DnDConstants;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Callable;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;
import javax.swing.SwingUtilities;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import org.jdesktop.swingx.JXTree;
import org.jdesktop.swingx.search.TreeSearchable;

/**
 *
 * @author David
 */
public class ElementTree extends JXTree
{

    private DefaultTreeModel treeModel;
    private HashMap<DefaultMutableTreeNode, UUID> nodeIds = new HashMap<DefaultMutableTreeNode, UUID>();
    private DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("Scene", true);
    private DefaultMutableTreeNode spatialsNode = new DefaultMutableTreeNode("Objects");
    private DefaultMutableTreeNode lightsNode = new DefaultMutableTreeNode("Lights");
    private DefaultMutableTreeNode filtersNode = new DefaultMutableTreeNode("Filters");
    private DefaultMutableTreeNode othersNode = new DefaultMutableTreeNode("Other");
    private DefaultMutableTreeNode selectedNode = null;
    private JPopupMenu addPopupMenu = new JPopupMenu();
    private AddMenu addMenu = new AddMenu();
    private String oldName;
    private boolean nameChangingLegit = false;
    private ControlsPopupMenu controlsPopupMenu = new ControlsPopupMenu();
    private boolean codeSelect = false;
    /*stolen*/
    private Insets autoscrollInsets = new Insets(20, 20, 20, 20);

    public void autoscroll(Point cursorLocation)
    {
        Insets insets = getAutoscrollInsets();
        Rectangle outer = getVisibleRect();
        Rectangle inner = new Rectangle(outer.x + insets.left, outer.y + insets.top, outer.width - (insets.left + insets.right), outer.height - (insets.top + insets.bottom));
        if (!inner.contains(cursorLocation))
        {
            Rectangle scrollRect = new Rectangle(cursorLocation.x - insets.left, cursorLocation.y - insets.top, insets.left + insets.right, insets.top + insets.bottom);
            scrollRectToVisible(scrollRect);
        }
    }

    public Insets getAutoscrollInsets()
    {
        return autoscrollInsets;
    }

    public static DefaultMutableTreeNode makeDeepCopy(DefaultMutableTreeNode node)
    {
        DefaultMutableTreeNode copy = new DefaultMutableTreeNode(node.getUserObject());
        for (Enumeration e = node.children(); e.hasMoreElements();)
        {
            copy.add(makeDeepCopy((DefaultMutableTreeNode) e.nextElement()));
        }
        return copy;
    }
    /*not stolen*/

    public void init()
    {
        setRolloverEnabled(true);
        setSearchable(new TreeSearchable(this));
        setRowHeight(20);
        new DefaultTreeTransferHandler(this, DnDConstants.ACTION_MOVE);
        setAutoscrolls(true);
        addMenu.setEnabled(true);
        addPopupMenu.add(addMenu);
        setEnabled(false);
        setEditable(true);
        getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
        addTreeSelectionListener(new TreeSelectionListener()
        {
            public void valueChanged(TreeSelectionEvent e)
            {
                try
                {
                    final DefaultMutableTreeNode tempNode = (DefaultMutableTreeNode) getLastSelectedPathComponent();
                    if (tempNode != null)
                    {
                        oldName = (String) tempNode.getUserObject();
                        selectedNode = tempNode;
                        try
                        {
                            CurrentData.getEditorWindow().getB3DApplication().setSelectedElement(nodeIds.get(tempNode));
                        } catch (NullPointerException npe)
                        {
                            CurrentData.getObserverDialog().printError("Error selecting Element chosen in Tree", npe);
                        }
                    }
                } catch (NullPointerException npe)
                {
                    CurrentData.getObserverDialog().printError("Error in TreeSelectionListener", npe);
                }
            }
        });
        addMouseListener(new MouseListener()
        {
            public void mouseClicked(MouseEvent e)
            {
            }

            public void mousePressed(MouseEvent e)
            {
            }

            public void mouseReleased(MouseEvent e)
            {
                CurrentData.getEditorWindow().getB3DApplication().setSelectedNode(
                        CurrentData.getEditorWindow().getB3DApplication().getSceneNode());
                if (SwingUtilities.isRightMouseButton(e))
                {
                    setSelectionRow(getClosestRowForLocation(e.getX(), e.getY()));
                }
                if (e.getButton() == MouseEvent.BUTTON3)  //controls
                {
                    if (CurrentData.getEditorWindow().getB3DApplication().getSelectedObject() != null)
                    {
                        if (CurrentData.getEditorWindow().getB3DApplication().getSelectedObject() instanceof Node)
                        {
                            addMenu.remove(addMenu.getObject3DMenu());
                            controlsPopupMenu.add(addMenu.getObject3DMenu());
                        } else
                        {
                            controlsPopupMenu.remove(addMenu.getObject3DMenu());
                            addMenu.add(addMenu.getObject3DMenu(), 0);
                        }
                    } else
                    {
                        controlsPopupMenu.remove(addMenu.getObject3DMenu());
                        addMenu.add(addMenu.getObject3DMenu(), 0);
                    }
                    controlsPopupMenu.popup(selectedNode, e.getX(), e.getY());
                } else if (e.getButton() == MouseEvent.BUTTON2)
                {
                    controlsPopupMenu.remove(addMenu.getObject3DMenu());
                    addMenu.add(addMenu.getObject3DMenu(), 0);
                    addPopupMenu.show(ElementTree.this, e.getX(), e.getY());
                }
            }

            public void mouseEntered(MouseEvent e)
            {
            }

            public void mouseExited(MouseEvent e)
            {
            }
        });
        addKeyListener(new KeyListener()
        {
            public void keyTyped(KeyEvent e)
            {
            }

            public void keyPressed(KeyEvent e)
            {
            }

            public void keyReleased(KeyEvent e)
            {
                if (e.getKeyCode() == KeyEvent.VK_DELETE)
                {
                    ElementTree.this.deleteSelected();
                } else if ((e.getKeyCode() == KeyEvent.VK_D) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0))
                {
                    if (CurrentData.getEditorWindow().getB3DApplication().getSelectedObject() != null)
                    {
                        duplicateSelected();
                    }
                }
            }
        });
        rootNode.removeAllChildren();
        rootNode.add(spatialsNode);
        rootNode.add(lightsNode);
        rootNode.add(filtersNode);
        rootNode.add(othersNode);
        treeModel = new DefaultTreeModel(rootNode, true);
        treeModel.addTreeModelListener(new RenameListener());
        setModel(treeModel);
        setCellRenderer(new ElementTreeCellRenderer(this));
    }

    public void sync()
    {
        synchronized (nodeIds)
        {
            nodeIds.clear();
            spatialsNode.removeAllChildren();
            lightsNode.removeAllChildren();
            filtersNode.removeAllChildren();
            othersNode.removeAllChildren();
            Collection elements = CurrentData.getEditorWindow().getB3DApplication().getElementList().getObjectHashMap().values();
            List<B3D_Element> list = new ArrayList(elements);
            Collections.sort(list, new Comparator<B3D_Element>()
            {
                public int compare(B3D_Element o1, B3D_Element o2)
                {
                    if (CurrentData.getConfiguration().getSettings().get("treesort").equals("a-z(cs)"))
                    {
                        return o1.getName().compareTo(o2.getName());
                    } else if (CurrentData.getConfiguration().getSettings().get("treesort").equals("a-z(no_cs)"))
                    {
                        return o1.getName().toLowerCase().compareTo(o2.getName().toLowerCase());
                    } else if (CurrentData.getConfiguration().getSettings().get("treesort").equals("z-a(cs)"))
                    {
                        return o1.getName().compareTo(o2.getName()) * -1;
                    } else
                    {
                        return o1.getName().toLowerCase().compareTo(o2.getName().toLowerCase()) * -1;
                    }
                }
            });
            for (B3D_Element element : list)
            {
                if (element instanceof B3D_Spatial)
                {
                    if (((B3D_Spatial) element).getParentID() == null)
                    {
                        handleChild(spatialsNode, element);
                    }
                } else if (element instanceof B3D_Light)
                {
                    DefaultMutableTreeNode tempNode = new DefaultMutableTreeNode(element.getName(), false);
                    nodeIds.put(tempNode, element.getID());
                    lightsNode.add(tempNode);
                } else if (element instanceof B3D_Filter)
                {
                    DefaultMutableTreeNode tempNode = new DefaultMutableTreeNode(element.getName(), false);
                    nodeIds.put(tempNode, element.getID());
                    filtersNode.add(tempNode);
                } else
                {
                    DefaultMutableTreeNode tempNode = new DefaultMutableTreeNode(element.getName(), false);
                    nodeIds.put(tempNode, element.getID());
                    othersNode.add(tempNode);
                }
            }
            treeModel = new DefaultTreeModel(rootNode, true);
            treeModel.addTreeModelListener(new RenameListener());
            setCellRenderer(new ElementTreeCellRenderer(this));
            setModel(treeModel);
            expandAll();
            updateSelection();
        }
    }

    private void handleChild(DefaultMutableTreeNode parentNode, B3D_Element element)
    {
        synchronized (nodeIds)
        {
            if (element != null)
            {
                if (!nodeIds.containsValue(element.getID())
                        && (nodeIds.containsValue(((B3D_Spatial) element).getParentID()) || parentNode.equals(spatialsNode)))
                {
                    DefaultMutableTreeNode tempNode = new DefaultMutableTreeNode(element.getName(), (CurrentData.getEditorWindow().getB3DApplication().getElementList().getObject(element) instanceof Node));
                    parentNode.add(tempNode);
                    nodeIds.put(tempNode, element.getID());
                    if (CurrentData.getEditorWindow().getB3DApplication().getElementList().getObject(element) instanceof Node)
                    {
                        Node node = (Node) CurrentData.getEditorWindow().getB3DApplication().getElementList().getObject(element);
                        for (Spatial spatial : node.getChildren())
                        {
                            handleChild(tempNode, CurrentData.getEditorWindow().getB3DApplication().getElementList().getElement(spatial));
                        }
                    }
                }
            }
        }
    }

    public void updateSelection()
    {
        synchronized (nodeIds)
        {
            if (!codeSelect)
            {
                if (CurrentData.getEditorWindow().getB3DApplication().getSelectedElement() != null)
                {
                    UUID selectedID = CurrentData.getEditorWindow().getB3DApplication().getSelectedElement().getID();
                    for (Map.Entry<DefaultMutableTreeNode, UUID> entry : nodeIds.entrySet())
                    {
                        if (entry.getValue().equals(selectedID))
                        {
                            TreePath tPath = new TreePath(treeModel.getPathToRoot(entry.getKey()));
                            setSelectionPath(tPath);
                        }
                    }
                }
            } else
            {
                codeSelect = false;
            }
            repaint();
        }
    }

    private void deleteSelected()
    {
        final String className = CurrentData.getEditorWindow().getB3DApplication().getSelectedElement().getClass().getName();
        if (CurrentData.getEditorWindow().getB3DApplication().getSelectedObject() instanceof Spatial)
        {
            CurrentData.getEditorWindow().getB3DApplication().enqueue(new Callable<Void>()
            {
                public Void call() throws Exception
                {
                    ((Spatial) CurrentData.getEditorWindow().getB3DApplication().getSelectedObject()).getParent().detachChild((Spatial) CurrentData.getEditorWindow().getB3DApplication().getSelectedObject());
                    CurrentData.getEditorWindow().getB3DApplication().getElementList().removeByObject(CurrentData.getEditorWindow().getB3DApplication().getSelectedObject());
                    CurrentData.getEditorWindow().getB3DApplication().setSelectedElement(null, null);
                    CurrentData.getEditorWindow().getEditPane().arrange(false);
                    sync();
                    return null;
                }
            });
            if (CurrentData.getEditorWindow().getB3DApplication().getSelectedObject() instanceof Node)
            {/*
                 synchronized (CurrentData.getEditorWindow().getB3DApplication().getNodeModels())
                 {
                 for (final NodeModel nm : CurrentData.getEditorWindow().getB3DApplication().getNodeModels())
                 {
                 if (nm.getNode().equals(CurrentData.getEditorWindow().getB3DApplication().getSelectedNode()))
                 {
                 CurrentData.getEditorWindow().getB3DApplication().getNodeModels().remove(nm);
                 CurrentData.getEditorWindow().getB3DApplication().enqueue(new Callable<Void>()
                 {
                 public Void call() throws Exception
                 {
                 System.out.println("YEEEEEEAH SHTI");
                 nm.getModel().removeFromParent();
                 nm.getLineNode().removeFromParent();
                 nm.getNode().removeFromParent();
                 return null;
                 }
                 });
                 CurrentData.getEditorWindow().getB3DApplication().getNodeModels().remove(nm);
                 }
                 }
                 }*/

            }
        } else if (CurrentData.getEditorWindow().getB3DApplication().getSelectedObject() instanceof Light)
        {
            CurrentData.getEditorWindow().getB3DApplication().enqueue(new Callable<Void>()
            {
                public Void call() throws Exception
                {
                    CurrentData.getEditorWindow().getB3DApplication().getSceneNode().removeLight(
                            (Light) CurrentData.getEditorWindow().getB3DApplication().getSelectedObject());
                    CurrentData.getEditorWindow().getB3DApplication().getElementList().removeByObject(CurrentData.getEditorWindow().getB3DApplication().getSelectedObject());
                    CurrentData.getEditorWindow().getB3DApplication().setSelectedElement(null, null);
                    CurrentData.getEditorWindow().getEditPane().arrange(false);
                    sync();
                    return null;
                }
            });
        } else if (CurrentData.getEditorWindow().getB3DApplication().getSelectedObject() instanceof Filter)
        {
            CurrentData.getEditorWindow().getB3DApplication().enqueue(new Callable<Void>()
            {
                public Void call() throws Exception
                {
                    CurrentData.getEditorWindow().getB3DApplication().getFilterPostProcessor().removeFilter(
                            (Filter) CurrentData.getEditorWindow().getB3DApplication().getSelectedObject());
                    CurrentData.getEditorWindow().getB3DApplication().getElementList().removeByObject(CurrentData.getEditorWindow().getB3DApplication().getSelectedObject());
                    CurrentData.getEditorWindow().getB3DApplication().setSelectedElement(null, null);
                    CurrentData.getEditorWindow().getEditPane().arrange(false);
                    sync();
                    return null;
                }
            });


        } else if (className.equals(B3D_MotionEvent.class.getName()))
        {
            CurrentData.getEditorWindow().getB3DApplication().enqueue(new Callable<Void>()
            {
                public Void call() throws Exception
                {
                    if (((B3D_MotionEvent) CurrentData.getEditorWindow().getB3DApplication().getSelectedElement()).getObject().equals(B3D_MotionEvent.Cam.CAM))
                    {
                        CurrentData.getEditorWindow().getB3DApplication().detachCam();
                    }
                    ((MotionEvent) CurrentData.getEditorWindow().getB3DApplication().getSelectedObject()).stop();
                    CurrentData.getEditorWindow().getB3DApplication().getMotionEvents().remove((MotionEvent) CurrentData.getEditorWindow().getB3DApplication().getSelectedObject());
                    CurrentData.getEditorWindow().getB3DApplication().getElementList().removeByObject(CurrentData.getEditorWindow().getB3DApplication().getSelectedObject());
                    CurrentData.getEditorWindow().getB3DApplication().setSelectedElement(null, null);
                    CurrentData.getEditorWindow().getEditPane().arrange(false);
                    sync();
                    return null;
                }
            });
        }
    }

    private void duplicateSelected()
    {
        if (!(CurrentData.getEditorWindow().getB3DApplication().getSelectedObject() instanceof Filter))
        {
            //System.out.println("Selected: " + CurrentData.getEditorWindow().getB3DApplication().getElementList().getObject(
            //        CurrentData.getEditorWindow().getB3DApplication().getSelectedElement()));
            final B3D_Element newElement = ObjectToElementConverter.convertToElement(CurrentData.getEditorWindow().getB3DApplication().getSelectedObject());
            final Object newObject = ElementToObjectConverter.converToObject(newElement);
            CurrentData.getEditorWindow().getB3DApplication().getElementList().putByElement(newElement, newObject);
            CurrentData.getEditorWindow().getB3DApplication().getElementList().putByObject(newObject, newElement);
            if (newObject instanceof Node)
            {
                CurrentData.getEditorWindow().getB3DApplication().setSelectedNode(CurrentData.getEditorWindow().getB3DApplication().getSelectedNode().getParent());
            }
            if (newObject instanceof Spatial)
            {
                CurrentData.getEditorWindow().getB3DApplication().enqueue(new Callable<Void>()
                {
                    public Void call() throws Exception
                    {
                        CurrentData.getEditorWindow().getB3DApplication().getSceneNode().attachChild((Spatial) newObject);
                        return null;
                    }
                });
            } else if (newObject instanceof Light)
            {
                CurrentData.getEditorWindow().getB3DApplication().getSceneNode().addLight((Light) newObject);
            } else if (newObject instanceof MotionEvent)
            {
                CurrentData.getEditorWindow().getB3DApplication().getMotionEvents().add((MotionEvent) newObject);
            }
            sync();
        } else
        {
            Toolkit.getDefaultToolkit().beep();
        }
    }

    private class ControlsPopupMenu extends JPopupMenu
    {

        private JMenuItem renameItem = new JMenuItem("Rename");
        private JMenuItem duplicateItem = new JMenuItem("Duplicate");
        private JMenuItem deleteItem = new JMenuItem("Delete");
        private JMenuItem jumpToItem = new JMenuItem("Jump to");
        private JMenuItem lookAtItem = new JMenuItem("Look at");
        private JMenuItem playItem = new JMenuItem();
        private JMenuItem stopItem = new JMenuItem("Stop");
        private JMenuItem numberElementsItem = new JMenuItem("Number elements");
        private JCheckBoxMenuItem showAllMotionPathsItem = new JCheckBoxMenuItem("Show all MotionPaths", CurrentData.getConfiguration().getSettings().get("showallmotionpaths").equals("true"));

        public ControlsPopupMenu()
        {
            numberElementsItem.addActionListener(new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    int number = 1;
                    for (Spatial spatial : ((Node) CurrentData.getEditorWindow().getB3DApplication().getSelectedObject()).getChildren())
                    {
                        spatial.setName(spatial.getName() + " [" + number + "]");
                        CurrentData.getEditorWindow().getB3DApplication().getElementList().getElement(spatial).setName(spatial.getName());
                        number++;
                    }
                    sync();
                }
            });
            showAllMotionPathsItem.addActionListener(new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    CurrentData.getConfiguration().getSettings().put("showallmotionpaths", "" + showAllMotionPathsItem.isSelected());
                    CurrentData.getConfiguration().save();
                    CurrentData.getEditorWindow().getB3DApplication().updateSelectedMotionPath();
                }
            });
            lookAtItem.addActionListener(new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    CurrentData.getEditorWindow().getB3DApplication().enqueue(new Callable<Void>()
                    {
                        public Void call() throws Exception
                        {
                            if (CurrentData.getEditorWindow().getB3DApplication().getSelectedObject() instanceof Spatial)
                            {
                                CurrentData.getEditorWindow().getB3DApplication().getCamera().lookAt(((Spatial) CurrentData.getEditorWindow().getB3DApplication().getSelectedObject()).getWorldTranslation(), Vector3f.UNIT_Y);
                            } else if (CurrentData.getEditorWindow().getB3DApplication().getSelectedObject() instanceof Light)
                            {
                                /*Only Spot-And PointLight have that Item*/
                                if (CurrentData.getEditorWindow().getB3DApplication().getSelectedObject() instanceof PointLight)
                                {
                                    CurrentData.getEditorWindow().getB3DApplication().getCamera().lookAt(((PointLight) CurrentData.getEditorWindow().getB3DApplication().getSelectedObject()).getPosition(), Vector3f.UNIT_Y);
                                } else
                                {
                                    CurrentData.getEditorWindow().getB3DApplication().getCamera().lookAt(((SpotLight) CurrentData.getEditorWindow().getB3DApplication().getSelectedObject()).getPosition(), Vector3f.UNIT_Y);
                                }
                            } else if (CurrentData.getEditorWindow().getB3DApplication().getSelectedObject() instanceof MotionEvent)
                            {
                                CurrentData.getEditorWindow().getB3DApplication().getCamera().lookAt(((MotionEvent) CurrentData.getEditorWindow().getB3DApplication().getSelectedObject()).getPath().getWayPoint(0), Vector3f.UNIT_Y);
                            }
                            return null;
                        }
                    });
                }
            });
            duplicateItem.addActionListener(new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    duplicateSelected();
                }
            });
            jumpToItem.addActionListener(new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    CurrentData.getEditorWindow().getB3DApplication().enqueue(new Callable<Void>()
                    {
                        public Void call() throws Exception
                        {
                            if (CurrentData.getEditorWindow().getB3DApplication().getSelectedObject() instanceof Spatial)
                            {
                                CurrentData.getEditorWindow().getB3DApplication().getCamera().setLocation(((Spatial) CurrentData.getEditorWindow().getB3DApplication().getSelectedObject()).getWorldTranslation());
                            } else if (CurrentData.getEditorWindow().getB3DApplication().getSelectedObject() instanceof Light)
                            {
                                /*Only Spot-And PointLight have that Item*/
                                if (CurrentData.getEditorWindow().getB3DApplication().getSelectedObject() instanceof PointLight)
                                {
                                    CurrentData.getEditorWindow().getB3DApplication().getCamera().setLocation(((PointLight) CurrentData.getEditorWindow().getB3DApplication().getSelectedObject()).getPosition());
                                } else
                                {
                                    CurrentData.getEditorWindow().getB3DApplication().getCamera().setLocation(((SpotLight) CurrentData.getEditorWindow().getB3DApplication().getSelectedObject()).getPosition());
                                }
                            } else if (CurrentData.getEditorWindow().getB3DApplication().getSelectedObject() instanceof MotionEvent)
                            {
                                CurrentData.getEditorWindow().getB3DApplication().getCamera().setLocation(((MotionEvent) CurrentData.getEditorWindow().getB3DApplication().getSelectedObject()).getPath().getWayPoint(0));
                            }
                            return null;
                        }
                    });
                }
            });
            deleteItem.addActionListener(new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    deleteSelected();
                }
            });
            playItem.addActionListener(new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    if (playItem.getText().equals("Play"))
                    {
                        ((MotionPathTaskPane) CurrentData.getEditorWindow().getEditPane().getCurrentEditPane()).play();
                    } else
                    {
                        ((MotionPathTaskPane) CurrentData.getEditorWindow().getEditPane().getCurrentEditPane()).pause();
                    }
                }
            });
            stopItem.addActionListener(new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    ((MotionPathTaskPane) CurrentData.getEditorWindow().getEditPane().getCurrentEditPane()).stop();
                }
            });
            renameItem.addActionListener(new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    String newName = JOptionPane.showInputDialog("New Name:", selectedNode.getUserObject());
                    if (newName.equals("LightModel") || newName.equals("NodeModel") || newName.equals("LightSymbol") || newName.equals("SkyBox"))
                    {
                        JOptionPane.showMessageDialog(null, "Name already taken for In-Editor stuff!", "Nope", JOptionPane.ERROR_MESSAGE);
                    } else
                    {
                        if (CurrentData.getEditorWindow().getB3DApplication().getSelectedObject() instanceof Spatial)
                        {
                            ((Spatial) CurrentData.getEditorWindow().getB3DApplication().getSelectedObject()).setName(newName);
                        } else if (CurrentData.getEditorWindow().getB3DApplication().getSelectedObject() instanceof Light)
                        {
                            ((Light) CurrentData.getEditorWindow().getB3DApplication().getSelectedObject()).setName(newName);
                        } else if (CurrentData.getEditorWindow().getB3DApplication().getSelectedObject() instanceof Filter)
                        {
                            ((Filter) CurrentData.getEditorWindow().getB3DApplication().getSelectedObject()).setName(newName);
                        }
                        CurrentData.getEditorWindow().getB3DApplication().getSelectedElement().setName(newName);
                        sync();
                    }
                }
            });
        }

        private void popup(DefaultMutableTreeNode selectedNode, int x, int y)
        {
            removeAll();
            if (nodeIds.get(selectedNode) != null)
            {
                if (CurrentData.getEditorWindow().getB3DApplication().getElementList().getElement(nodeIds.get(selectedNode)) instanceof B3D_Spatial)
                {
                    if (CurrentData.getEditorWindow().getB3DApplication().getSelectedObject() instanceof Node)
                    {
                        add(addMenu.getObject3DMenu());
                        add(numberElementsItem);
                        add(new JSeparator());
                        CurrentData.getEditorWindow().getB3DApplication().setSelectedNode(
                                (Node) CurrentData.getEditorWindow().getB3DApplication().getSelectedObject());
                    }
                    add(duplicateItem);
                    add(lookAtItem);
                    add(jumpToItem);
                    add(renameItem);
                    add(deleteItem);
                } else if (selectedNode.getParent().equals(lightsNode))
                {
                    add(duplicateItem);
                    if (!(CurrentData.getEditorWindow().getB3DApplication().getSelectedObject() instanceof AmbientLight)
                            && !(CurrentData.getEditorWindow().getB3DApplication().getSelectedObject() instanceof DirectionalLight))
                    {
                        add(lookAtItem);
                        add(jumpToItem);
                    }
                    add(renameItem);
                    add(deleteItem);
                } else if (selectedNode.getParent().equals(filtersNode))
                {
                    if (!(CurrentData.getEditorWindow().getB3DApplication().getSelectedElement() instanceof B3D_Shadow))
                    {
                        add(duplicateItem);
                    }
                    add(renameItem);
                    add(deleteItem);
                } else if (CurrentData.getEditorWindow().getB3DApplication().getSelectedElement() instanceof B3D_MotionEvent)
                {
                    if (((MotionEvent) CurrentData.getEditorWindow().getB3DApplication().getElementList().getObject(
                            CurrentData.getEditorWindow().getB3DApplication().getSelectedElement())).getPlayState().equals(PlayState.Playing))
                    {
                        playItem.setText("Pause");
                    } else
                    {
                        playItem.setText("Play");
                    }
                    add(playItem);
                    if (!((MotionEvent) CurrentData.getEditorWindow().getB3DApplication().getElementList().getObject(
                            CurrentData.getEditorWindow().getB3DApplication().getSelectedElement())).getPlayState().equals(PlayState.Stopped))
                    {
                        add(stopItem);
                    }
                    add(new JSeparator(JSeparator.HORIZONTAL));
                    add(duplicateItem);
                    add(lookAtItem);
                    add(jumpToItem);
                    add(renameItem);
                    add(deleteItem);
                } else
                {
                    add(showAllMotionPathsItem);
                }
            } else
            {
                add(showAllMotionPathsItem);
            }

            show(ElementTree.this, x, y);
        }
    }

    class RenameListener implements TreeModelListener
    {

        public void treeNodesChanged(TreeModelEvent e)
        {
            DefaultMutableTreeNode tempNode = (DefaultMutableTreeNode) getLastSelectedPathComponent();
            if (!tempNode.equals(rootNode)
                    && !tempNode.equals(spatialsNode)
                    && !tempNode.equals(lightsNode)
                    && !tempNode.equals(filtersNode)
                    && !tempNode.equals(othersNode))
            {
                try
                {
                    if (tempNode.getUserObject().toString().equals("LightModel") || tempNode.getUserObject().toString().equals("LightSymbol") || tempNode.getUserObject().toString().equals("SkyBox"))
                    {
                        nameChangingLegit = false;
                        tempNode.setUserObject(oldName);
                    } else
                    {
                        CurrentData.getEditorWindow().getB3DApplication().getSelectedElement().setName(tempNode.getUserObject().toString());
                        Object actualObject = CurrentData.getEditorWindow().getB3DApplication().getElementList().getObject(CurrentData.getEditorWindow().getB3DApplication().getSelectedElement());
                        if (actualObject instanceof Light)
                        {
                            ((Light) actualObject).setName(tempNode.getUserObject().toString());
                        } else if (actualObject instanceof Filter)
                        {
                            ((Filter) actualObject).setName(tempNode.getUserObject().toString());
                        } else if (actualObject instanceof Spatial)
                        {
                            ((Spatial) actualObject).setName(tempNode.getUserObject().toString());
                        }
                        nameChangingLegit = true;
                        sync();
                    }
                    CurrentData.getEditorWindow().getB3DApplication().setSelectedElement(nodeIds.get(tempNode));
                } catch (NullPointerException npe)
                {
                    CurrentData.getObserverDialog().printError("Error while renaming", npe);
                }
            } else
            {
                rootNode.setUserObject("Scene");
                spatialsNode.setUserObject("Objects");
                lightsNode.setUserObject("Lights");
                filtersNode.setUserObject("Filters");
                othersNode.setUserObject("Other");
            }
            if (!nameChangingLegit)
            {
                JOptionPane.showMessageDialog(null, "Name already taken for In-Editor stuff!", "Nope", JOptionPane.ERROR_MESSAGE);
            }
        }

        public void treeNodesInserted(TreeModelEvent e)
        {
        }

        public void treeNodesRemoved(TreeModelEvent e)
        {
        }

        public void treeStructureChanged(TreeModelEvent e)
        {
        }
    }

    public DefaultMutableTreeNode getSelectedNode()
    {
        return selectedNode;
    }

    public DefaultMutableTreeNode getSpatialsNode()
    {
        return spatialsNode;
    }

    public DefaultMutableTreeNode getLightsNode()
    {
        return lightsNode;
    }

    public DefaultMutableTreeNode getFiltersNode()
    {
        return filtersNode;
    }

    public DefaultMutableTreeNode getOthersNode()
    {
        return othersNode;
    }

    public void setCodeSelect(boolean codeSelect)
    {
        this.codeSelect = codeSelect;
    }

    public HashMap<DefaultMutableTreeNode, UUID> getNodeIds()
    {
        return nodeIds;
    }

    public DefaultMutableTreeNode getRootNode()
    {
        return rootNode;
    }
}
